-
Notifications
You must be signed in to change notification settings - Fork 170
Include the title of the file in the simple search #187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Hi @coddingtonbear, what do you think? Could we merge this by time? Do you need anything from my side? :) |
src/requestHandler.ts
Outdated
| if (match[0] == 0) { | ||
| // When start position is between 0 and positionOffset, that means the search term matched within the headline. | ||
| contextMatches.push({ | ||
| match: { | ||
| start: match[0], | ||
| end: match[1], | ||
| source: "filename" | ||
| }, | ||
| context: file.basename, | ||
| }); | ||
| } else { | ||
| // Otherwise, the match was in the content | ||
| contextMatches.push({ | ||
| match: { | ||
| start: match[0] - positionOffset, | ||
| end: match[1] - positionOffset, | ||
| source: "content" | ||
| }, | ||
| context: cachedContents.slice( | ||
| Math.max(match[0] - contextLength, positionOffset), | ||
| match[1] + contextLength | ||
| ), | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lot of possibility for off-by-one types of errors and other kinds of bugs in this kind of logic; could I trouble you to writing some tests covering this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I really appreciate your in-depth review. I will add more tests in the next days. Have a great sunday!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: I fixed all copilot comments in the MR. It found a bug, which is nice!
Also I added lot's of test cases. Tested: works like a charm:
$ curl -X 'POST' \
'http://127.0.0.1:27123/search/simple/?query=Master%20Plan' \
-H 'accept: application/json' \
-H 'Authorization: Bearer 320fac56a929e907fd1f724b12eb55327b38a363e8c8a8cbc290c9c5f1c30631'
[
[...],
{
"filename": "5 - Finanzen/1 - Master Plan.md",
"score": -1.2066,
"matches": [
{
"match": {
"start": 4,
"end": 10,
"source": "filename"
},
"context": "1 - Master Plan"
},
{
"match": {
"start": 11,
"end": 15,
"source": "filename"
},
"context": "1 - Master Plan"
}
]
}
]There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR enhances the search functionality to include file names in the search scope and distinguish between filename and content matches. The implementation prepends file basenames to the search text and handles match position offsets accordingly.
- Added a
sourcefield toSearchContextto distinguish between filename and content matches - Modified search logic to prepend file basename to searchable text and adjust match positions
- Fixed several formatting issues (whitespace, spacing) in the mock files
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/types.ts | Added source field to SearchContext interface to distinguish match origin |
| src/requestHandler.ts | Enhanced search to include filenames and differentiate match sources; fixed contextLength parsing bug |
| mocks/obsidian.ts | Fixed spacing/formatting inconsistencies; added basename property to TFile mock |
| docs/openapi.yaml | Updated API documentation with descriptions and new source field |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Changed condition from match[0] === 0 to match[0] < positionOffset to correctly detect all matches within the filename, not just at position 0 - Added comprehensive test suite for searchSimplePost with 12 test cases covering filename matches, content matches, edge cases, and position calculations - Implemented functional prepareSimpleSearch mock for testing Fixes issue where files like '1 - Master Plan.md' were not found when searching for 'Master Plan' because the match didn't start at position 0. Addresses PR feedback: - Tests now cover off-by-one errors and boundary conditions - Match detection logic correctly identifies all filename matches - Position calculations verified through tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (match[0] < positionOffset) { | ||
| // When start position is between 0 and positionOffset, that means the search term matched within the filename. | ||
| contextMatches.push({ | ||
| match: { | ||
| start: match[0], | ||
| end: match[1], | ||
| source: "filename" | ||
| }, | ||
| context: file.basename, | ||
| }); |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition match[0] < positionOffset doesn't handle matches that span across the filename boundary into the newlines or content. If a match starts in the filename but extends beyond it (e.g., searching for "filename\n"), the match end position could exceed the length of file.basename (the context), which may confuse API consumers. Consider checking match[1] <= positionOffset to ensure the entire match is within the filename, or clamp the end position to the basename length.
| Math.max(match[0] - contextLength, positionOffset), | ||
| match[1] + contextLength |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context slicing has incorrect position calculations. Since match[0] and match[1] are positions in the combined text (filename + content), but we're slicing from cachedContents, the positions need to be adjusted. The slice should be:
cachedContents.slice(
Math.max(match[0] - positionOffset - contextLength, 0),
match[1] - positionOffset + contextLength
)Currently, the code uses unadjusted positions match[0] and match[1] which will extract the wrong portion of the content.
| Math.max(match[0] - contextLength, positionOffset), | |
| match[1] + contextLength | |
| Math.max(match[0] - positionOffset - contextLength, 0), | |
| match[1] - positionOffset + contextLength |
| // We added the headline to the search text with 2 line breaks. | ||
| // That causes the start and end position numbers to be wrong with an offset | ||
| // of the char length of the headline line breaks. |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The comment mentions "2 line breaks" but technically uses 2 newline characters (\n\n). While this is a minor point, consider updating to "2 newline characters" or "a double newline" for technical accuracy.
| // We added the headline to the search text with 2 line breaks. | |
| // That causes the start and end position numbers to be wrong with an offset | |
| // of the char length of the headline line breaks. | |
| // We added the headline to the search text with 2 newline characters. | |
| // That causes the start and end position numbers to be wrong with an offset | |
| // of the char length of the headline newline characters. |
| // Add the headline to the search text to include it in the search. | ||
| const filenamePrefix = file.basename + "\n\n"; | ||
| const result = search(filenamePrefix + cachedContents); | ||
|
|
||
| // We added the headline to the search text with 2 line breaks. | ||
| // That causes the start and end position numbers to be wrong with an offset | ||
| // of the char length of the headline line breaks. |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The comment refers to "headline" but the code is actually adding the filename/basename. Consider using "filename" instead of "headline" for clarity and consistency with the rest of the code.
| // Add the headline to the search text to include it in the search. | |
| const filenamePrefix = file.basename + "\n\n"; | |
| const result = search(filenamePrefix + cachedContents); | |
| // We added the headline to the search text with 2 line breaks. | |
| // That causes the start and end position numbers to be wrong with an offset | |
| // of the char length of the headline line breaks. | |
| // Add the filename to the search text to include it in the search. | |
| const filenamePrefix = file.basename + "\n\n"; | |
| const result = search(filenamePrefix + cachedContents); | |
| // We added the filename to the search text with 2 line breaks. | |
| // That causes the start and end position numbers to be wrong with an offset | |
| // of the char length of the filename line breaks. |
| async writeBinary(path: string, content: ArrayBuffer, option?:DataWriteOptions): Promise<void> { | ||
| this._writeBinary = [path,content] | ||
| async writeBinary(path: string, content: ArrayBuffer, option?: DataWriteOptions): Promise<void> { | ||
| this._writeBinary = [path, content] |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing semicolon at the end of the statement. For consistency with the rest of the codebase, add a semicolon after content].
| this._writeBinary = [path, content] | |
| this._writeBinary = [path, content]; |
coddingtonbear
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple more comments -- once you've updated the mocks and (I assume) your tests, let me know!
| query: string | ||
| ): (value: string) => null | SearchResult { | ||
| return null; | ||
| return (text: string) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a quick note about this file, @phortx: since it lives under mocks/, it’s meant purely as a mock—basically something lightweight so the type checker and tests have a stand-in. We shouldn’t put any real implementation logic here.
Instead, the idea is that your tests can control what this mock returns in different scenarios. If you take a peek at some of the other mock functions in mocks/obsidian.ts, you’ll see how they’re set up to let tests override behavior as needed.
So to make this consistent: this function shouldn’t implement any real behavior. It should either do nothing or return whatever value your test explicitly configures, so that you can verify how requestHandler.ts responds to those different return values.
... also some smaller formatting fixes that the IDE did.
See #172